# 方式1： 得到生成器
from collections import Iterable

g = (x * 3 for x in range(20))
print(type(g))

print(g.__next__())
print(g.__next__())
# 方式2：调用系统的next()方法
print(next(g))  # 如果生成器产生的元素用完了就会抛出异常

"""
yield会让线程暂停
只要函数中出现了 yield 关键字，说明此函数就不是函数了，变成生成器了
利用函数构建生成器步骤：
1.定义一个函数，函数中使用yield关键字
2.调用函数，接受调用的结果
3.得到的结果就是生成器
4.借助于next()或者__next__()函数生成内容
"""


def func():
    n = 0
    while True:
        n += 1
        yield n  # 相当于return n+线程暂停
        pass
    pass


g = func()
print(g.__next__())  # 调用的时候底层会在yield n这个地方返回并暂停
print(g.__next__())  # 底层会从上面暂停的地方继续执行一次，然后继续return n+暂停

"""
生成器生成的两种方式：
1. 通过列表推倒式方式
    g=(x+1 for x in range(6))
2. 函数+yield
    def func():
        ...
        yield
    g=func()
    产生元素：
        1. next(g)  --> 每次调用都会产生一个新的元素，如果元素产生完毕，再次调用的话就会产生异常
        2. 生成器自己的方法：
            g.__next__()
            g.send(value)
            
生成器的应用： 协程
"""

# 可迭代的对象： 1. 生成器， 2.元组 列表 集合 字典 字符串
list1 = [1, 2, 3, 4, 5]
b = isinstance(list1, Iterable)  # 判断是否可迭代
print(b)
g = (x + 1 for x in range(10))
b = isinstance(g, Iterable)
print(b)

"""
迭代器：
    迭代式访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。
    迭代器对象从集合的第一个元素开始访问，直到所有的元素被访问完结束。
    迭代器只能往前不会后退。
    可以被next()函数调用并不断返回下一个值的对象称为迭代器：Iterator
可迭代的是不是肯定就是迭代器？
    答案：错误
        生成器肯定就是迭代器
但是可以把list转换为迭代器 ---- >调用 iter()函数进行转换（元组，字典这些都可以转换）    
"""
list1 = [1, 2, 3, 4, 5]
print(next(list1))  # 会报错，此时list1不是一个迭代器
list1 = iter(list1)  # iter把可迭代的对象转换为迭代器就可以调用next()函数
print(next(list1))
print(next(list1))
